package com.ssy.lingxi.member.merchant.serviceimpl.mobile;

import com.ssy.lingxi.common.constant.Constants;
import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.constant.manage.ShopTypeEnum;
import com.ssy.lingxi.common.constant.member.MemberStatusEnum;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.common.utils.PasswordUtil;
import com.ssy.lingxi.common.utils.TokenUtil;
import com.ssy.lingxi.component.redis.service.IRedisUtils;
import com.ssy.lingxi.member.merchant.api.constant.MemberRelationTypeEnum;
import com.ssy.lingxi.member.merchant.config.ServiceConfig;
import com.ssy.lingxi.member.merchant.config.ServiceVariable;
import com.ssy.lingxi.member.merchant.entity.*;
import com.ssy.lingxi.member.merchant.model.bo.MobileLoginBO;
import com.ssy.lingxi.member.merchant.model.vo.basic.request.PhoneVO;
import com.ssy.lingxi.member.merchant.model.vo.login.request.MobileLoginVO;
import com.ssy.lingxi.member.merchant.model.vo.login.request.MobilePhoneLoginVO;
import com.ssy.lingxi.member.merchant.repository.MemberRelationRepository;
import com.ssy.lingxi.member.merchant.repository.MemberUserChannelRepository;
import com.ssy.lingxi.member.merchant.repository.MemberUserRepository;
import com.ssy.lingxi.member.merchant.repository.RoleRepository;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberCacheService;
import com.ssy.lingxi.member.merchant.service.feign.ISmsFeignService;
import com.ssy.lingxi.member.merchant.service.mobile.IMobileWechatAppletLoginService;
import com.ssy.lingxi.member.merchant.utils.SecurityStringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 郑小翠
 * @version 2.02.18
 * @date 2022-03-23
 */
@Service
public class MobileWechatAppletLoginServiceImpl implements IMobileWechatAppletLoginService {

    @Resource
    private MemberUserRepository memberUserRepository;

    @Resource
    private MemberUserChannelRepository memberUserChannelRepository;

    @Resource
    private RoleRepository roleRepository;

    @Resource
    private MemberRelationRepository relationRepository;

    @Resource
    private IBaseMemberCacheService memberCacheService;

    @Resource
    private ISmsFeignService smsFeignService;

    @Resource
    private JdbcTemplate jdbcTemplate;

    @Resource
    private IRedisUtils redisUtils;

    /**
     * 账号登录
     *
     * @param headers Http头部信息
     * @param loginVO 接口参数
     * @return 登录用户信息
     */
    @Override
    public Wrapper<MobileLoginBO> accountLogin(HttpHeaders headers, MobileLoginVO loginVO) {
        memberCacheService.checkMobileRequestHeader(headers);
        // 从用户表中读取用户信息
        MemberUserDO memberUserDO = memberUserRepository.findLoginUser(loginVO.getAccount(), loginVO.getAccount(), MemberRelationTypeEnum.OTHER.getCode());

        // 校验密码
        if (memberUserDO == null || !PasswordUtil.instance().checkPassword(memberUserDO.getPassword(), loginVO.getPassword()) || memberUserDO.getIsSales().equals(0)) {
            return Wrapper.fail(ResponseCode.USER_ACCOUNT_OR_PASSWORD_INCORRECT);
        }
        if (memberUserDO.getStatus().equals(EnableDisableStatus.DISABLE.getCode())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_HAS_BEEN_FROZEN);
        }

        MemberDO memberDO = memberUserDO.getMember();
        if (ObjectUtils.isEmpty(memberDO)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        // 根据用户Id和会员Id返回角色Id
        List<MemberUserChannelDO> memberUserChannelList = memberUserChannelRepository.findByMemberIdAndUserId(memberDO.getId(), memberUserDO.getId());
        Long roleId = memberUserChannelList.get(0).getRoleId();
        // 根据角色Id找到角色
        RoleDO roleDO = roleRepository.findById(roleId).orElse(null);
        if (ObjectUtils.isEmpty(roleDO)) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        // 会员关系主键Id
        Long memberRelationId = memberUserChannelList.get(0).getMemberRelationId();

        MemberRelationDO memberRelationDO = relationRepository.findById(memberRelationId).orElse(null);
        if (ObjectUtils.isEmpty(memberRelationDO)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_RELATION_DOES_NOT_EXIST);
        }

        // 生成token
        String token = TokenUtil.instance().getToken();

        // 缓存用户信息
        UserLoginCacheDTO loginCache = new UserLoginCacheDTO();

        loginCache.setUserId(memberUserDO.getId());
        loginCache.setUserType(memberUserDO.getTypeEnum());
        loginCache.setLoginTime(System.currentTimeMillis());
        loginCache.setTokenExpireMinutes(ServiceVariable.WEB_LOGIN_TOKEN_EXPIRE_MINUTES);
        loginCache.setUserName(StringUtils.hasLength(memberUserDO.getName()) ? memberUserDO.getName() : "");
        loginCache.setUserPhone(memberUserDO.getPhone());
        loginCache.setUserJobTitle(StringUtils.hasLength(memberUserDO.getJobTitle()) ? memberUserDO.getJobTitle() : "");
        loginCache.setLogo(StringUtils.hasLength(memberUserDO.getLogo()) ? memberUserDO.getLogo() : "");
        loginCache.setUserOrgName(memberUserDO.getOrg() == null ? "" : memberUserDO.getOrg().getTitle());
        loginCache.setUserRoleName(CollectionUtils.isEmpty(memberUserDO.getRoles()) ? "" : memberUserDO.getRoles().stream().map(MemberRoleDO::getRoleName).collect(Collectors.joining(",")));
        loginCache.setLoginSource(2);
        loginCache.setMemberId(memberDO.getId());
        loginCache.setCompany(memberDO.getName());
        loginCache.setMemberRoleId(roleDO.getId());
        loginCache.setMemberRoleName(roleDO.getRoleName());

        redisUtils.set(token, loginCache, ServiceConfig.MOBILE_LOGIN_TOKEN_EXPIRE_MINUTES, Constants.REDIS_USER_INDEX);

        // 记录最后一次登录时间
        updateUserLastLoginTimeAsync(memberUserDO.getId());

        // 返回结果
        MobileLoginBO mobileLoginBO = new MobileLoginBO(memberRelationDO.getOuterStatus(), memberDO, memberUserDO, roleDO.getId(), roleDO.getMemberType().getTypeEnum(), token, ServiceConfig.MOBILE_LOGIN_TOKEN_EXPIRE_MINUTES, null, null, null);

        return Wrapper.success(mobileLoginBO);
    }


    /**
     * 发送“手机号登录”的短信验证码
     *
     * @param headers Http头部信息
     * @param phoneVO 接口参数
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> sendPhoneLoginSmsCode(HttpHeaders headers, PhoneVO phoneVO) {
        memberCacheService.checkMobileRequestHeader(headers);

        MemberUserDO memberUserDO = memberUserRepository.findFirstByCountryCodeAndPhoneAndRelType(phoneVO.getCountryCode(), phoneVO.getPhone(), MemberRelationTypeEnum.OTHER.getCode());

        if (memberUserDO == null || ObjectUtils.isEmpty(memberUserDO.getIsSales()) || 1 != memberUserDO.getIsSales()) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (memberUserDO.getMember() == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        List<MemberRelationDO> relationDOList = relationRepository.findBySubMemberIdAndRelType(memberUserDO.getMember().getId(), MemberRelationTypeEnum.PLATFORM.getCode());
        if (relationDOList.stream().noneMatch(relationDO -> relationDO.getStatus().equals(MemberStatusEnum.NORMAL.getCode()))) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_HAS_BEEN_FROZEN);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.MOBILE_PHONE_LOGIN_SMS_CODE_REDIS_KEY_PREFIX + memberUserDO.getId();
        memberCacheService.setString(cacheKey, smsCode, ServiceConfig.MOBILE_PHONE_LOGIN_SMS_CACHED_TIME_MINUTES * 60);

        return smsFeignService.sendMobilePhoneLoginSms(memberUserDO.getCountryCode(), memberUserDO.getPhone(), smsCode, ServiceVariable.SMSCODE_CACHED_TIME_MINUTES);

    }

    /**
     * 手机号登录
     *
     * @param headers Http头部信息
     * @param loginVO 接口参数
     * @return 登录用户信息
     */
    @Override
    public Wrapper<MobileLoginBO> phoneLogin(HttpHeaders headers, MobilePhoneLoginVO loginVO) {
        memberCacheService.checkMobileRequestHeader(headers);

        // 商城类型
        ShopTypeEnum shopType = ShopTypeEnum.parseCode(loginVO.getShopType());
        if (shopType == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_SHOP_MISMATCHED);
        }

        // 从用户表中读取用户信息
        MemberUserDO memberUserDO = memberUserRepository.findFirstByCountryCodeAndPhoneAndRelType(loginVO.getCountryCode(), loginVO.getPhone(), MemberRelationTypeEnum.OTHER.getCode());
        if (memberUserDO == null || memberUserDO.getStatus().equals(EnableDisableStatus.DISABLE.getCode())) {
            return Wrapper.fail(ResponseCode.USER_ACCOUNT_OR_PASSWORD_INCORRECT);
        }

        MemberDO memberDO = memberUserDO.getMember();
        if (memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        // 校验短信验证码
        String cacheKey = ServiceConfig.MOBILE_PHONE_LOGIN_SMS_CODE_REDIS_KEY_PREFIX + memberUserDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if (!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if (!loginVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        // 根据用户Id和会员Id返回角色Id
        List<MemberUserChannelDO> memberUserChannelDO = memberUserChannelRepository.findByMemberIdAndUserId(memberDO.getId(), memberUserDO.getId());
        Long roleId = memberUserChannelDO.get(0).getRoleId();
        // 根据角色Id找到角色
        RoleDO roleDO = roleRepository.findById(roleId).orElse(null);
        if (ObjectUtils.isEmpty(roleDO)) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        // 会员关系主键Id
        Long memberRelationId = memberUserChannelDO.get(0).getMemberRelationId();

        MemberRelationDO memberRelationDO = relationRepository.findById(memberRelationId).orElse(null);
        if (ObjectUtils.isEmpty(memberRelationDO)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_RELATION_DOES_NOT_EXIST);
        }

        // 生成token
        String token = TokenUtil.instance().getToken();

        // 缓存用户信息
        UserLoginCacheDTO loginCache = new UserLoginCacheDTO();

        loginCache.setUserId(memberUserDO.getId());
        loginCache.setUserType(memberUserDO.getTypeEnum());
        loginCache.setLoginTime(System.currentTimeMillis());
        loginCache.setTokenExpireMinutes(ServiceVariable.WEB_LOGIN_TOKEN_EXPIRE_MINUTES);
        loginCache.setUserName(StringUtils.hasLength(memberUserDO.getName()) ? memberUserDO.getName() : "");
        loginCache.setUserPhone(memberUserDO.getPhone());
        loginCache.setUserJobTitle(StringUtils.hasLength(memberUserDO.getJobTitle()) ? memberUserDO.getJobTitle() : "");
        loginCache.setLogo(StringUtils.hasLength(memberUserDO.getLogo()) ? memberUserDO.getLogo() : "");
        loginCache.setUserOrgName(memberUserDO.getOrg() == null ? "" : memberUserDO.getOrg().getTitle());
        loginCache.setUserRoleName(CollectionUtils.isEmpty(memberUserDO.getRoles()) ? "" : memberUserDO.getRoles().stream().map(MemberRoleDO::getRoleName).collect(Collectors.joining(",")));
        loginCache.setLoginSource(2);
        loginCache.setMemberId(memberDO.getId());
        loginCache.setCompany(memberDO.getName());
        loginCache.setMemberRoleId(roleDO.getId());
        loginCache.setMemberRoleName(roleDO.getRoleName());

        redisUtils.set(token, loginCache, ServiceConfig.MOBILE_LOGIN_TOKEN_EXPIRE_MINUTES * 60, Constants.REDIS_USER_INDEX);

        // 记录最后一次登录时间
        updateUserLastLoginTimeAsync(memberUserDO.getId());

        // 返回结果
        MobileLoginBO mobileLoginBO = new MobileLoginBO(memberRelationDO.getOuterStatus(), memberDO, memberUserDO, roleDO.getId(), roleDO.getMemberType().getTypeEnum(), token, ServiceConfig.MOBILE_LOGIN_TOKEN_EXPIRE_MINUTES, null, null, null);

        return Wrapper.success(mobileLoginBO);
    }

    /**
     * 更新用户最后一次登录时间
     *
     * @param userId 用户Id
     */
    @Async
    public void updateUserLastLoginTimeAsync(Long userId) {
        String sql = String.format("update ms_mc_member_user set last_login_time = '%s' where id = %d", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), userId);
        jdbcTemplate.update(sql);
    }
}
